package com.dingwen.treasure.tkmybatis.controller;

import cn.hutool.core.convert.Convert;
import com.dingwen.treasure.base.controller.BaseCrudController;
import com.dingwen.treasure.base.controller.BaseViewController;
import com.dingwen.treasure.base.convert.model.impl.AbstractBeanConvertImpl;
import com.dingwen.treasure.base.util.ReflectUtil;
import com.dingwen.treasure.base.pojo.vo.Result;
import com.dingwen.treasure.base.pojo.vo.ResultGenerator;
import com.dingwen.treasure.beansearch.controller.AbstractBaseControllerBeanSearchImpl;
import com.dingwen.treasure.tkmybatis.service.base.BaseService;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.io.Serializable;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 　AbstractBaseControllerTKMybatisImpl: TODO 完善、逻辑删除完善
 * 基础 crud 封装 controller tk mybatis 实现 </br>
 * <p>泛型说明：</p>
 * <ul>
 *     <li>P： po 持久化对象</li>
 *     <li>D: dto 数据传输对象</li>
 *     <li>V： vo 视图对象</li>
 * </ul>
 *
 * <p> 优化记录： </p>
 * <ul>
 *     <li> getDto（）优化：多线程条件下加同步锁较少调用次数,只是获取值，修改为 volatile 一旦赋值多线程立刻可见 </li>
 * </ul>
 * <p>
 * 　@author dingwen
 * 　@date 2022/7/4
 */
public abstract class AbstractBaseCrudControllerTkMybatisImpl<
        P extends Serializable, // 实体
        D extends AbstractBeanConvertImpl<P, D, V>, // 数据传输对象
        V // 视图对象
        >
       extends AbstractBaseControllerBeanSearchImpl<P> implements BaseCrudController<D>, BaseViewController {

    /**
     * 数据传输对象
     */
    protected volatile D dto;


    /**
     * baseService
     */
    @Autowired
    protected BaseService<P> baseService;

    /**
     * 根据Id查询，返回单个实体
     *
     * @param id 数据表主键
     * @return {@link Result}
     */
    @Override
    @ApiOperation("根据主键查询,返回单个对象")
    @ApiOperationSupport(author = "dingwen")
    @ApiImplicitParam(value = "主键", name = "id")
    @GetMapping("/{id}")
    public Result findById(@PathVariable(value = "id") Serializable id) {

        // 数据库对象
        P po = (P)baseService.getById(Convert.toLong(id));
        // 数据传输对象
        D dto = getDto();
        if (enableBoToVo()) {
            // 需要进行转换
            // 视图对象
            V vo = dto.poToVo(po);
            return ResultGenerator.genSuccessResult(vo);
        }
        return ResultGenerator.genSuccessResult(po);
    }

    /**
     * 根据List<id>查找实体
     *
     * @param ids id 传参示例： 1,2,3 集合长度至少为2
     * @return {@link Result}
     */
    @Override
    public Result findByIds(List<Serializable> ids) {
        return null;
    }

    /**
     * 无条件查询所有
     *
     * @return {@link Result}
     */
    @Override
    @ApiOperation("查询所有，返回对象 List")
    @ApiOperationSupport(author = "dingwen")
    @GetMapping
    public Result findAll() {
        // 数据库对象
        List<P> pos = baseService.getAll();
        if (enableBoToVo()) {
            // 页面对象
            List<V> vos = pos.parallelStream()
                    .map(po -> getDto().poToVo(po))
                    .collect(Collectors.toList());
            return ResultGenerator.genSuccessResult(vos);
        }
        return ResultGenerator.genSuccessResult(pos);
    }

    /**
     * 无条件分页查询
     *
     * @param pageSize 页面大小
     * @param pageNum  页面num
     * @return {@link Result}
     */
    @Override
    public Result page(Integer pageSize, Integer pageNum) {
        return null;
    }

    /**
     * 获取数据表总记录条数
     *
     * @return {@link Result}
     */
    @Override
    public Result count() {
        return null;
    }

    /**
     * 通过 id 查询是否存在 </br>
     * <ol>
     *     <li>true: 存在</li>
     *     <li>false: 不存在</li>
     * </ol>
     *
     * @param id 主键id
     * @return {@link Result}
     */
    @Override
    @ApiOperation("根据对象 id 查询对象是否存在,返回布尔值")
    @ApiOperationSupport(author = "dingwen")
    @GetMapping("/exists/{id}")
    public Result<Boolean> existsById(@PathVariable("id") Serializable id) {
        return ResultGenerator.genSuccessResult(baseService.existById(id));
    }

    /**
     * 修改,对象 id ,主键必须有值,默认获取 t 中的 id 属性
     *
     * @param dto 数据传输对象
     * @return {@link Result}
     */
    @Override
    public Result modify(D dto) {
        return null;
    }

    /**
     * 修改
     * 修改,对象 id ,主键必须有值
     *
     * @param dto            数据传输对象
     * @param fieldNameForId 指定Id 字段名称
     * @param id  主键id（符合rest接口定义规范）
     * @return {@link Result}
     */
    @Override
    public Result modify(D dto, Serializable id,String fieldNameForId) {
        return null;
    }

    /**
     * 修改
     * 修改,批量修改,对象主键必须要有值,,默认获取 t 中的 id 属性
     *
     * @param dtos           数据传输对象列表
     * @param fieldNameForId 指定Id 字段名称
     * @return {@link Result}
     */
    @Override
    public Result batchModify(List<D> dtos, String fieldNameForId) {
        return null;
    }

    /**
     * 修改,批量修改,对象主键必须要有值
     *
     * @param dtos 数据传输对象列表
     * @return {@link Result}
     */
    @Override
    public Result batchModify(List<D> dtos) {
        return null;
    }

    /**
     * 保存
     *
     * @param dto 数据传输对象
     * @return {@link Result}
     */
    @Override
    @ApiOperation("保存一个对象到数据库，返回布尔值")
    @ApiOperationSupport(author = "dingwen")
    @ApiImplicitParam(value = "数据传输对象", name = "dto", dataType = "body")
    @PostMapping
    public Result save(@RequestBody D dto) {
        return ResultGenerator.genSuccessResult(baseService.add(dto.dtoToPo(dto)));
    }

    /**
     * 批量保存
     *
     * @param dtos 数据传输对象列表
     * @return {@link Result}
     */
    @Override
    public Result batchSave(List<D> dtos) {
        return null;
    }

    /**
     * 删除
     *
     * @param id id
     * @return {@link Result}
     */
    @Override
    @ApiOperation("删除单条记录，返回布尔值")
    @ApiOperationSupport(author = "dingwen")
    @ApiImplicitParam(name = "id", value = "主键")
    @DeleteMapping("/{id}")
    public Result removeById(@PathVariable(value = "id") Serializable id) {
        return ResultGenerator.genResult(baseService.removeById(id));
    }

    /**
     * 根据主键集合批量删除
     *
     * @param ids id
     * @return {@link Result}
     */
    @Override
    public Result batchRemoveByIds(List<Serializable> ids) {
        return null;
    }

    /**
     * 获取dto
     *
     * @return {@link D} dto 数据传输对象
     */
    @SneakyThrows(Throwable.class)
    public D getDto() {
        if (!Objects.isNull(dto)) {
            return dto;
        }
        Class<D> dtoClass = ReflectUtil.getClassForGeneric(1, this);
        dto = dtoClass.newInstance();
        return dto;
    }
}
